<template>
  <div class="ai-chat">
    <el-row :gutter="20">
      <!-- 左侧常见问题 -->
      <el-col :span="6">
        <el-card class="qa-card">
          <template #header>
            <div class="card-header">
              <h3>常见问题</h3>
            </div>
          </template>
          <div class="qa-list">
            <div 
              v-for="qa in commonQuestions" 
              :key="qa.id"
              class="qa-item"
              @click="handleQuickQuestion(qa.question)"
            >
              <el-icon><QuestionFilled /></el-icon>
              <span>{{ qa.question }}</span>
            </div>
          </div>
        </el-card>
      </el-col>

      <!-- 中间聊天区域 -->
      <el-col :span="12">
        <el-card class="chat-card">
          <template #header>
            <div class="card-header">
              <h2>智慧问诊</h2>
              <p>AI医疗助手将为您解答健康问题</p>
            </div>
          </template>
          
          <div class="chat-container" ref="chatContainerRef">
            <div class="chat-messages">
              <div 
                v-for="(message, index) in messages" 
                :key="index"
                :class="['message', message.role === 'user' ? 'user' : 'assistant']"
              >
                <el-avatar 
                  :size="40"
                  :src="message.role === 'user' ? userAvatar : assistantAvatar"
                />
                <div class="message-content">
                  <div class="message-text" v-html="formatMessage(message.content)"></div>
                  <div v-if="message.media" class="message-media">
                    <img v-if="message.media.image" :src="message.media.image" alt="上传的图片" />
                    <video v-if="message.media.video" :src="message.media.video" controls />
                  </div>
                  <span class="message-time">{{ message.time }}</span>
                </div>
              </div>
            </div>
          </div>
          
          <div class="chat-input">
            <div class="media-preview" v-if="Object.values(mediaPreview).some(v => v)">
              <div v-for="(url, type) in mediaPreview" :key="type" class="media-item" v-if="url">
                <div class="media-content">
                  <div class="media-icon">
                    <el-icon v-if="type === 'image'" :size="24"><Picture /></el-icon>
                    <el-icon v-if="type === 'video'" :size="24"><VideoPlay /></el-icon>
                  </div>
                  <img v-if="type === 'image'" :src="url" alt="图片预览" />
                  <video v-if="type === 'video'" :src="url" controls />
                  <div class="media-info">
                    <span class="media-type">{{ getMediaTypeLabel(type) }}</span>
                    <span class="media-size" v-if="mediaInputs[type]">
                      {{ formatFileSize(mediaInputs[type].size) }}
                    </span>
                  </div>
                </div>
                <el-button type="danger" circle size="small" class="delete-btn" @click="clearMediaPreview(type)">
                  <el-icon><Delete /></el-icon>
                </el-button>
              </div>
            </div>
            
            <div class="input-area">
              <div class="input-box">
                <div class="uploaded-files" v-if="Object.values(mediaInputs).some(v => v)">
                  <div v-for="(file, type) in mediaInputs" :key="type" v-if="file" class="file-tag">
                    <el-icon :size="14">
                      <Picture v-if="type === 'image'" />
                      <VideoPlay v-if="type === 'video'" />
                    </el-icon>
                    <span>{{ getMediaTypeLabel(type) }}</span>
                  </div>
                </div>
                <el-input
                  v-model="inputMessage"
                  type="textarea"
                  :rows="3"
                  :placeholder="getInputPlaceholder()"
                  :disabled="loading"
                  @keyup.enter.exact="handleSend"
                />
              </div>
              
              <div class="input-actions">
                <div class="media-inputs">
                  <el-upload
                    class="media-upload"
                    action=""
                    :show-file-list="false"
                    :auto-upload="false"
                    accept="image/*"
                    @change="(file) => handleMediaInput('image', file.raw)"
                  >
                    <el-button :class="['upload-btn', {'is-active': !!mediaInputs.image}]">
                      <el-icon><Picture /></el-icon>
                      <span>图片</span>
                    </el-button>
                  </el-upload>
                  
                  <el-upload
                    class="media-upload"
                    action=""
                    :show-file-list="false"
                    :auto-upload="false"
                    accept="video/*"
                    @change="(file) => handleMediaInput('video', file.raw)"
                  >
                    <el-button :class="['upload-btn', {'is-active': !!mediaInputs.video}]">
                      <el-icon><VideoCamera /></el-icon>
                      <span>视频</span>
                    </el-button>
                  </el-upload>

                  <el-button
                    :class="['voice-btn', { 'is-recording': isRecording }]"
                    @mousedown="startRecording"
                    @mouseup="stopRecording"
                    @mouseleave="stopRecording"
                  >
                    <el-icon><Microphone /></el-icon>
                    <span>{{ isRecording ? '正在录音...' : '按住说话' }}</span>
                  </el-button>
                </div>

                <div class="input-actions-right">
                  <el-button 
                    type="primary" 
                    :loading="loading"
                    :disabled="!canSend"
                    @click="handleSend"
                  >
                    发送
                  </el-button>
                  <el-button @click="clearChat">清空对话</el-button>
                </div>
              </div>
            </div>
          </div>
        </el-card>
      </el-col>

      <!-- 右侧使用说明 -->
      <el-col :span="6">
        <el-card class="guide-card">
          <template #header>
            <div class="card-header">
              <h3>使用指南</h3>
            </div>
          </template>
          <div class="guide-content">
            <div class="guide-item">
              <el-icon><InfoFilled /></el-icon>
              <div class="guide-text">
                <h4>注意事项</h4>
                <p>AI助手仅提供健康咨询建议，不能替代医生的专业诊断。如有严重症状，请及时就医。</p>
              </div>
            </div>
            <div class="guide-item">
              <el-icon><List /></el-icon>
              <div class="guide-text">
                <h4>使用建议</h4>
                <ul>
                  <li>请详细描述您的症状</li>
                  <li>可以询问健康知识</li>
                  <li>建议参考多个来源</li>
                </ul>
              </div>
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick, onUnmounted, computed } from 'vue'
import { sendMultiModalMessage, sendSpeechRecognition } from '@/api/ai_chat'
import { ElMessage } from 'element-plus'
import { 
  QuestionFilled, 
  InfoFilled,
  List,
  Picture,
  VideoCamera,
  VideoPlay,
  Delete,
  Document,
  Close,
  Microphone
} from '@element-plus/icons-vue'

const chatContainerRef = ref(null)
const loading = ref(false)
const inputMessage = ref('')
const isRecording = ref(false)
const mediaRecorder = ref(null)

// 常见问题列表
const commonQuestions = [
  { id: 1, question: "感冒发烧该如何处理？" },
  { id: 2, question: "如何预防心血管疾病？" },
  { id: 3, question: "失眠应该怎么调理？" },
  { id: 4, question: "颈椎不适怎么办？" },
  { id: 5, question: "如何科学减肥？" }
]

const messages = ref([
  {
    role: 'assistant',
    content: '您好！我是AI医疗助手，请问有什么可以帮您？',
    time: new Date().toLocaleTimeString()
  }
])

const userAvatar = 'https://picsum.photos/200/200?random=1'
const assistantAvatar = 'https://picsum.photos/200/200?random=2'

const mediaInputs = ref({
  image: null,
  video: null
})

const mediaPreview = ref({
  image: null,
  video: null
})

const getMediaTypeLabel = (type) => {
  const labels = {
    image: '图片',
    video: '视频'
  }
  return labels[type] || type
}

const getInputPlaceholder = () => {
  if (loading.value) return '正在思考中...'
  if (isRecording.value) return '正在录音...'
  if (Object.values(mediaInputs.value).some(v => v)) {
    return '请输入关于上传媒体的问题...'
  }
  return '输入您想问的问题，或按住"按住说话"进行语音输入'
}

const canSend = computed(() => {
  return !loading.value && (
    inputMessage.value.trim() || 
    Object.values(mediaInputs.value).some(v => v)
  )
})

const formatMessage = (content) => {
  if (typeof content === 'string') {
    return content.replace(/\n/g, '<br>')
  }
  if (Array.isArray(content)) {
    return content
      .filter(item => item.type === 'text')
      .map(item => item.text)
      .join('\n')
      .replace(/\n/g, '<br>')
  }
  return ''
}

const scrollToBottom = async () => {
  await nextTick()
  if (chatContainerRef.value) {
    window.requestAnimationFrame(() => {
      chatContainerRef.value.scrollTop = chatContainerRef.value.scrollHeight
    })
  }
}

const handleMediaInput = async (type, file) => {
  try {
    mediaInputs.value[type] = file
    mediaPreview.value[type] = URL.createObjectURL(file)
  } catch (error) {
    console.error('媒体处理失败:', error)
    ElMessage.error(error.message || '媒体处理失败')
  }
}

const clearMediaPreview = (type) => {
  if (mediaPreview.value[type]) {
    URL.revokeObjectURL(mediaPreview.value[type])
  }
  mediaPreview.value[type] = null
  mediaInputs.value[type] = null
}

const handleSend = async () => {
  if (!inputMessage.value.trim() && !Object.values(mediaInputs.value).some(v => v)) {
    ElMessage.warning('请输入问题或上传媒体文件')
    return
  }
  
  loading.value = true
  let currentResponse = ''
  
  try {
    // 添加用户消息
    const userMessage = {
      role: 'user',
      content: inputMessage.value,
      time: new Date().toLocaleTimeString(),
      media: {}
    }
    
    // 添加媒体预览
    Object.entries(mediaInputs.value).forEach(([type, file]) => {
      if (file) {
        userMessage.media[type] = mediaPreview.value[type]
      }
    })
    
    messages.value.push(userMessage)
    await scrollToBottom()
    
    // 创建助手消息占位符
    const assistantMessage = {
      role: 'assistant',
      content: '',
      time: new Date().toLocaleTimeString()
    }
    messages.value.push(assistantMessage)
    await scrollToBottom()
    
    // 发送请求并处理流式响应
    const stream = await sendMultiModalMessage({
      text: inputMessage.value,
      ...mediaInputs.value,
      history: messages.value.slice(0, -2).map(msg => ({
        role: msg.role,
        content: msg.content
      }))
    })
    
    // 处理流式响应
    try {
      for await (const chunk of stream) {
        if (chunk.content) {
          // 实时添加每个字符
          currentResponse += chunk.content
          assistantMessage.content = currentResponse
          // 使用requestAnimationFrame确保平滑滚动
          requestAnimationFrame(() => {
            scrollToBottom()
          })
        }
      }
    } catch (error) {
      console.error('处理响应流时出错:', error)
      ElMessage.error(error.message || '处理响应时出错')
      messages.value.pop() // 移除助手消息
      throw error
    }
    
    // 清空输入和媒体
    inputMessage.value = ''
    Object.keys(mediaInputs.value).forEach(type => {
      clearMediaPreview(type)
    })
    
  } catch (error) {
    console.error('发送失败:', error)
    messages.value.pop() // 移除助手消息
    messages.value.pop() // 移除用户消息
    ElMessage.error(error.message || '发送失败，请稍后重试')
  } finally {
    loading.value = false
    await scrollToBottom()
  }
}

const handleQuickQuestion = (question) => {
  inputMessage.value = question
  handleSend()
}

const clearChat = () => {
  messages.value = [messages.value[0]]
  scrollToBottom()
}

const formatFileSize = (bytes) => {
  if (bytes === 0) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

// 检查浏览器是否支持音频录制
const checkAudioSupport = () => {
  if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
    ElMessage.error('您的浏览器不支持音频录制功能，请使用最新版本的Chrome、Firefox或Edge浏览器')
    return false
  }
  return true
}

const startRecording = async () => {
  if (!checkAudioSupport()) return
  
  try {
    // 请求麦克风权限
    const stream = await navigator.mediaDevices.getUserMedia({ 
      audio: {
        sampleRate: { ideal: 16000 },
        channelCount: { ideal: 1 },
        echoCancellation: false,
        noiseSuppression: false,
        autoGainControl: false
      } 
    })
    
    // 创建音频上下文
    const audioContext = new (window.AudioContext || window.webkitAudioContext)({
      sampleRate: 16000
    })
    
    // 创建音频源节点
    const sourceNode = audioContext.createMediaStreamSource(stream)
    
    // 创建音频处理器
    // 使用4096作为缓冲区大小，这是2的12次方，在256到16384之间
    const bufferSize = 4096
    const processorNode = audioContext.createScriptProcessor(bufferSize, 1, 1)
    
    // 存储音频数据
    const audioChunks = []
    
    // 处理音频数据
    processorNode.onaudioprocess = (e) => {
      const inputData = e.inputBuffer.getChannelData(0)
      const audioData = new Float32Array(inputData)
      const pcmData = convertFloat32ToInt16(audioData)
      audioChunks.push(pcmData)
    }
    
    // 连接节点
    sourceNode.connect(processorNode)
    processorNode.connect(audioContext.destination)
    
    // 设置状态
    isRecording.value = true
    mediaRecorder.value = {
      stream,
      audioContext,
      sourceNode,
      processorNode,
      audioChunks
    }
    
    // 添加错误处理
    stream.oninactive = () => {
      console.log('音频流已关闭')
      stopRecording()
    }
    
    stream.getAudioTracks().forEach(track => {
      track.onended = () => {
        console.log('音频轨道已结束')
        stopRecording()
      }
    })
    
  } catch (error) {
    console.error('开启录音失败:', error)
    if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {
      ElMessage.error('请在浏览器设置中允许访问麦克风')
    } else if (error.name === 'NotFoundError') {
      ElMessage.error('未找到麦克风设备')
    } else if (error.name === 'NotReadableError') {
      ElMessage.error('麦克风设备被占用')
    } else {
      ElMessage.error('无法访问麦克风：' + error.message)
    }
  }
}

const stopRecording = async () => {
  if (!mediaRecorder.value) return
  
  try {
    if (loading.value) return  // 如果已经在处理中，直接返回
    isRecording.value = false
    loading.value = true
    
    // 停止录音
    const { stream, audioContext, sourceNode, processorNode, audioChunks } = mediaRecorder.value
    
    // 断开连接
    sourceNode.disconnect()
    processorNode.disconnect()
    
    // 停止所有音频轨道
    stream.getTracks().forEach(track => {
      track.stop()
      stream.removeTrack(track)
    })
    
    // 关闭音频上下文
    if (audioContext.state !== 'closed') {
      await audioContext.close()
    }
    
    // 检查是否有音频数据
    if (audioChunks.length === 0) {
      throw new Error('未录制到音频数据')
    }
    
    // 合并音频数据
    const totalLength = audioChunks.reduce((acc, chunk) => acc + chunk.length, 0)
    if (totalLength === 0) {
      throw new Error('录音时长太短')
    }
    
    const audioData = new Int16Array(totalLength)
    let offset = 0
    
    audioChunks.forEach(chunk => {
      audioData.set(chunk, offset)
      offset += chunk.length
    })
    
    // 发送音频数据
    const result = await sendSpeechRecognition(audioData.buffer)
    if (result.success && result.text) {
      // 将识别结果添加到输入框，如果输入框已有内容则添加到末尾
      const recognizedText = result.text
      const currentInput = inputMessage.value || ''
      
      inputMessage.value = currentInput
        ? `${currentInput.trim()} ${recognizedText}`
        : recognizedText
        
      ElMessage.success('语音识别成功')
      
      // 使用 nextTick 等待 DOM 更新完成
      await nextTick()
      
      // 确保输入框保持焦点，并且不影响其他组件
      const textarea = document.querySelector('.input-box .el-textarea__inner')
      if (textarea) {
        textarea.focus()
        // 将光标移动到文本末尾
        const len = textarea.value.length
        textarea.setSelectionRange(len, len)
      }
      
      // 确保聊天容器滚动到底部
      await scrollToBottom()
    } else {
      throw new Error(result.error || '语音识别失败')
    }
  } catch (error) {
    console.error('语音识别失败:', error)
    ElMessage.error(error.message || '语音识别失败')
  } finally {
    loading.value = false
    mediaRecorder.value = null
  }
}

// 将Float32Array转换为Int16Array
const convertFloat32ToInt16 = (float32Array) => {
  const int16Array = new Int16Array(float32Array.length)
  for (let i = 0; i < float32Array.length; i++) {
    const s = Math.max(-1, Math.min(1, float32Array[i]))
    int16Array[i] = s < 0 ? s * 0x8000 : s * 0x7FFF
  }
  return int16Array
}

onMounted(() => {
  scrollToBottom()
})

onUnmounted(() => {
  // 清理资源
  Object.values(mediaInputs.value).forEach(file => {
    if (file) {
      URL.revokeObjectURL(file)
    }
  })
})
</script>

<style scoped>
.ai-chat {
  padding: 20px;
  height: calc(100vh - 100px);
}

.chat-card {
  height: 100%;
  display: flex;
  flex-direction: column;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.chat-container {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
  margin-bottom: 20px;
  scroll-behavior: smooth;
}

.chat-messages {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.message {
  display: flex;
  gap: 12px;
  max-width: 80%;
  animation: fadeIn 0.3s ease-out;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.message.user {
  margin-left: auto;
  flex-direction: row-reverse;
}

.message-content {
  background: #f4f4f5;
  padding: 12px 16px;
  border-radius: 12px;
  position: relative;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  transition: all 0.3s ease;
}

.message.user .message-content {
  background: #409eff;
  color: white;
}

.message-content:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.message .el-avatar {
  width: 40px !important;
  height: 40px !important;
  flex-shrink: 0;
  border: 2px solid #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s ease;
}

.message .el-avatar:hover {
  transform: scale(1.1);
}

.message-time {
  font-size: 12px;
  color: #999;
  margin-top: 4px;
  display: block;
}

.message.user .message-time {
  color: rgba(255, 255, 255, 0.8);
}

.chat-input {
  padding: 20px;
  border-top: 1px solid #eee;
  background: #fff;
  width: 100%;
  box-sizing: border-box;
}

.input-area {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 100%;
}

.input-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
  width: 100%;
}

.media-inputs {
  display: flex;
  gap: 8px;
  align-items: center;
}

.upload-btn,
.voice-btn {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 8px 12px;
  border-radius: 8px;
  transition: all 0.3s;
  height: 36px;
}

.upload-btn:hover,
.upload-btn.is-active,
.voice-btn:hover {
  color: #409eff;
  background: #ecf5ff;
  transform: translateY(-1px);
}

.upload-btn.is-active {
  border-color: #409eff;
}

.voice-btn {
  position: relative;
  overflow: hidden;
}

.voice-btn::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  background: rgba(64, 158, 255, 0.1);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  transition: width 0.3s, height 0.3s;
}

.voice-btn.is-recording::before {
  width: 200%;
  height: 200%;
  animation: pulse 1.5s infinite;
}

.voice-btn.is-recording {
  color: #fff;
  background-color: #409eff;
}

.voice-btn.is-recording:hover {
  color: #fff;
  background-color: #409eff;
}

.input-actions-right {
  display: flex;
  gap: 12px;
}

.input-box {
  position: relative;
  background: #fff;
  border-radius: 8px;
  transition: all 0.3s ease;
  flex: 1;
  min-width: 0;
}

.input-box:focus-within {
  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}

.input-box .el-textarea {
  width: 100%;
}

.input-box .el-textarea__inner {
  border-radius: 8px;
  padding: 12px;
  min-height: 80px !important;
  resize: none;
  transition: all 0.3s ease;
  width: 100%;
  box-sizing: border-box;
}

.input-box .el-textarea__inner:focus {
  box-shadow: none;
}

.media-preview {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 16px;
  padding: 12px;
  background: #f5f7fa;
  border-radius: 8px;
  animation: slideDown 0.3s ease-out;
}

@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.media-item {
  position: relative;
  width: 160px;
  background: white;
  border-radius: 8px;
  padding: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.media-item:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.media-content img,
.media-content video {
  width: 100%;
  height: 120px;
  object-fit: cover;
  border-radius: 4px;
  transition: all 0.3s ease;
}

.media-content img:hover,
.media-content video:hover {
  transform: scale(1.02);
}

.delete-btn {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 24px;
  height: 24px;
  padding: 0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.5);
  border: none;
  color: white;
  cursor: pointer;
  transition: all 0.3s;
  opacity: 0;
  transform: scale(0.8);
}

.media-item:hover .delete-btn {
  opacity: 1;
  transform: scale(1);
}

.delete-btn:hover {
  background: rgba(0, 0, 0, 0.8);
  transform: scale(1.1);
}

.qa-card, .guide-card {
  height: 100%;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.qa-card:hover, .guide-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
}

.qa-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.qa-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.3s;
}

.qa-item:hover {
  background: #f5f7fa;
  transform: translateX(4px);
}

.guide-content {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.guide-item {
  display: flex;
  gap: 12px;
  padding: 12px;
  border-radius: 8px;
  transition: all 0.3s ease;
}

.guide-item:hover {
  background: #f5f7fa;
  transform: translateX(4px);
}

.guide-text h4 {
  margin: 0 0 8px 0;
  color: #409eff;
}

.guide-text ul {
  margin: 0;
  padding-left: 20px;
}

.card-header {
  margin-bottom: 0;
  padding: 16px;
  border-bottom: 1px solid #eee;
}

.card-header h2, 
.card-header h3 {
  margin: 0;
  color: #303133;
}

.message-media {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.message-media img,
.message-media video {
  max-width: 300px;
  max-height: 200px;
  object-fit: contain;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.message-media img:hover,
.message-media video:hover {
  transform: scale(1.02);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.uploaded-files {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 1;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.file-tag {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  background: #ecf5ff;
  color: #409eff;
  border-radius: 4px;
  font-size: 12px;
  animation: fadeIn 0.3s ease-out;
}

.file-tag .el-icon {
  margin-right: 2px;
}

/* 滚动条样式 */
.chat-container::-webkit-scrollbar {
  width: 6px;
}

.chat-container::-webkit-scrollbar-track {
  background: #f5f7fa;
  border-radius: 3px;
}

.chat-container::-webkit-scrollbar-thumb {
  background: #c0c4cc;
  border-radius: 3px;
}

.chat-container::-webkit-scrollbar-thumb:hover {
  background: #909399;
}
</style>